package common.toolkit.java.util;

import static common.toolkit.java.constant.BaseConstant.WORD_SEPARATOR;
import static common.toolkit.java.constant.EmptyObjectConstant.EMPTY_STRING;
import static common.toolkit.java.constant.SvnConstant.SVN_BRANCHES;
import static common.toolkit.java.constant.SvnConstant.SVN_TRUNK;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import common.toolkit.java.constant.RegExpConstant;
import common.toolkit.java.util.io.FileUtil;


/**
 * 类说明: SVN相关工具类
 *
 * @author 银时 yinshi.nc@taobao.com
 */
public class SvnUtil {


    static Pattern unifiedDiffChunkRe = Pattern.compile("^@@\\s+-(?:(\\d+)(?:,(\\d+))?)\\s+\\+(?:(\\d+)(?:,(\\d+))?)\\s+@@$");


    /**
     * parse the path of file in project from it's svn path.
     *
     * @return e.g.
     * reviewboardtest/pagecache-webx3-ga-example/pagecache-webx3-ga
     * -example-web/src/main/webapp/WEB-INF/sadfsadfsqlmapadsaf.xml
     * @throws Exception
     */
    public static String parseFileProjectPathFromSvnPath(String svnPath) throws Exception {
        if (StringUtil.isBlank(svnPath)) {
            return EMPTY_STRING;
        }

        int index = -1;

        int indexOfTrunk = svnPath.indexOf(SVN_TRUNK);
        int indexOfBranches = svnPath.indexOf(SVN_BRANCHES);

        // 必须找到第一个trunk或branches, 文件路径自有的关键字不能算.
        if (-1 == indexOfTrunk && -1 != indexOfBranches) {
            index = indexOfBranches + SVN_BRANCHES.length() + 1;
        } else if (-1 == indexOfBranches && -1 != indexOfTrunk) {
            index = indexOfTrunk + SVN_TRUNK.length() + 1;
        } else if (-1 == indexOfBranches && -1 == indexOfTrunk) {
            throw new Exception(svnPath + " is a illegal svn path");
        } else if (-1 != indexOfBranches && -1 != indexOfTrunk) {
            if (indexOfBranches < indexOfTrunk) {
                index = indexOfBranches + SVN_BRANCHES.length() + 1;
            } else if (indexOfBranches > indexOfTrunk) {
                index = indexOfTrunk + SVN_TRUNK.length() + 1;
            }
        }
        return svnPath.substring(index);
    }

    /**
     * parse the path of file in project from it's svn path with svn prefix
     *
     * @return e.g.
     * trunk/reviewboardtest/pagecache-webx3-ga-example/pagecache-webx3
     * -ga-example-web/src/main/webapp/WEB-INF/asdfsqlmapadsaf.xml
     * @throws Exception
     */
    public static String parseFileProjectPathFromSvnPathWithSvnPrefix(String svnPath) throws Exception {
        if (StringUtil.isBlank(svnPath)) {
            return EMPTY_STRING;
        }

        int index = -1;

        int indexOfTrunk = svnPath.indexOf(SVN_TRUNK);
        int indexOfBranches = svnPath.indexOf(SVN_BRANCHES);

        // 必须找到第一个trunk或branches, 文件路径自有的关键字不能算.
        if (-1 == indexOfTrunk && -1 != indexOfBranches) {
            index = indexOfBranches;
        } else if (-1 == indexOfBranches && -1 != indexOfTrunk) {
            index = indexOfTrunk;
        } else if (-1 == indexOfBranches && -1 == indexOfTrunk) {
            throw new Exception(svnPath + " is a illegal svn path");
        } else if (-1 != indexOfBranches && -1 != indexOfTrunk) {
            if (indexOfBranches < indexOfTrunk) {
                index = indexOfBranches;
            } else if (indexOfBranches > indexOfTrunk) {
                index = indexOfTrunk;
            }
        }
        return svnPath.substring(index);
    }


    /**
     * 将一个diff文本按照不同文件进行拆解
     *
     * @param diffContentAll 待拆解的内容
     * @param pathList       完整文件名
     * @return Map<String,String>  <文件名, diff内容>
     * @throws Exception
     */
    public static Map<String, String> splitDiff(String diffContentAll, List<String> pathList) throws Exception {
        if (diffContentAll == null || diffContentAll.isEmpty()
                || pathList == null || pathList.isEmpty()) {
            return null;
        }
        Map<String, String> targetMap = new LinkedHashMap<String, String>();
        if (pathList.size() == 1) {
            targetMap.put(pathList.get(0), diffContentAll);
            return targetMap;
        }

        //将所有文件分隔行分隔成一个易于区分的分隔符
        String tempString = diffContentAll.replaceAll(RegExpConstant.REGEX_OF_DIFF_INDEX, WORD_SEPARATOR);

        String[] diffSplit = tempString.split(WORD_SEPARATOR);

        // i = 1 是因为第一个是多余的且空.
        for (int i = 1; i < diffSplit.length; i++) {

            String diffContent = EMPTY_STRING;
            String key = EMPTY_STRING;
            try {
                diffContent = diffSplit[i];
            } catch (Exception e) {
                throw new Exception("数组越界: 从diffSplit获取数据, length=" + diffSplit.length + " 但是i= " + i);
            }
            try {
                key = pathList.get(i - 1);
            } catch (Exception e) {
                throw new Exception("List越界: 从pathList获取数据, size=" + pathList.size() + " 但是i= " + (i - 1));
            }

            targetMap.put(key, diffContent);
        }

        return targetMap;
    }


    /**
     * 拼装DIFF内容到新文件
     *
     * @param originalFileName 原文件的完整文件名
     * @param diffFileName     Diff文件的完整文件名
     * @return String 拼装后的完整内容
     */
    public static String patchDiffFile(String originalFileName, String diffFileName) throws Exception {

        List<String> original = FileUtil.fileToListByLine(originalFileName);
        List<String> patched = FileUtil.fileToListByLine(diffFileName);

        return patchDiff(original, patched);
    }


    /**
     * 拼装DIFF内容到新文件
     *
     * @param originalFileContent 原文件的内容
     * @param diffFileContent     Diff文件的内容
     * @return String 拼装后的完整内容
     */
    public static String patchDiffContent(String originalFileContent, String diffFileContent) throws Exception {

        List<String> original = FileUtil.stringToListByLine(originalFileContent);
        List<String> patched = FileUtil.stringToListByLine(diffFileContent);

        return patchDiff(original, patched);
    }


    /**
     * 拼装DIFF内容到新文件
     *
     * @param originalFileLineList 原文件按行的内容集合
     * @param diffFileLineList     Diff文件按行的内容集合
     * @return String 拼装后的完整内容
     */
    private static String patchDiff(List<String> originalFileLineList, List<String> diffFileLineList) {

        Map<Integer, String> mapInsert = new LinkedHashMap<Integer, String>();
        Map<Integer, String> mapDelete = new LinkedHashMap<Integer, String>();

        int index = 0;
        boolean flag = false;

        for (String line : diffFileLineList) {

            Matcher matcherOfRevision = unifiedDiffChunkRe.matcher(line);

            /** 解析出初始行号 */
            if (matcherOfRevision.find()) {
                String str = matcherOfRevision.group();
                str = str.replaceAll("@@", "").trim().split(",")[0].replace("-", "");
                index = Integer.parseInt(str);
                flag = true;
                continue;
            }

            if (flag) {
                // 如果是要从原来文件中删除的
                if (line.startsWith("-")) {
                    continue;
                } else if (line.startsWith("+")) {
                    mapInsert.put(index, line);
                    index++;
                } else {
                    index++;
                }
            }
        }

        index = 0;
        flag = false;
        for (String line : diffFileLineList) {

            Matcher matcherOfRevision = unifiedDiffChunkRe.matcher(line);

            /** 解析出初始行号 */
            if (matcherOfRevision.find()) {
                String str = matcherOfRevision.group();
                str = str.replaceAll("@@", "").trim().split(",")[0].replace("-", "");
                index = Integer.parseInt(str);
                flag = true;
                continue;
            }

            if (flag) {
                // 如果是要从原来文件中删除的
                if (line.startsWith("+")) {
                    continue;
                } else if (line.startsWith("-")) {
                    mapDelete.put(index, line);
                    index++;
                } else {
                    index++;
                }
            }
        }

        //现在已经获得了两个可以用的ADD和DELETE的map了.
        List<String> tempFile = new ArrayList<String>();
        List<String> newFile = new ArrayList<String>();
        int lineIndex = 0;

        //先处理mapDelete
        for (String line : originalFileLineList) {
            lineIndex++;
            String lineContentDelete = mapDelete.get(lineIndex);

            if (null == lineContentDelete) {
                //此行没有变动
                tempFile.add(line);
            }

        }

        //现在处理mapInsert
        lineIndex = 0;
        for (String line : tempFile) {
            lineIndex++;
            String lineContentInsert = mapInsert.get(lineIndex);

            if (null == lineContentInsert) {
                newFile.add(line);
            } else {

                boolean isOk = true;
                while (isOk) {
                    newFile.add(lineContentInsert.replaceFirst("\\+", ""));
                    mapInsert.put(lineIndex, null);
                    lineIndex++;
                    lineContentInsert = mapInsert.get(lineIndex);

                    if (null == lineContentInsert)
                        isOk = false;
                }

                newFile.add(line);

            }

        }


        //接下去要把mapInsert中多余的加入newFile中去.
        for (int _index : mapInsert.keySet()) {
            String lineContent = mapInsert.get(_index);
            if (null == lineContent)
                continue;

            newFile.add(lineContent.replaceFirst("\\+", ""));
        }

        StringBuilder newContent = new StringBuilder();
        if ("\n".equalsIgnoreCase(newFile.get(newFile.size() - 1))) {
            newFile.remove(newFile.size() - 1);
        }

        for (String newLine : newFile) {
            newContent.append(newLine).append("\n");
        }

        return newContent.toString();
    }


}